﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Practices.Unity;
using Sern.Abstracts.Tracker.DataContracts;
using Sern.Abstracts.Tracker.ServiceContracts;
using Sern.Common;
using Sern.ServiceImplementation.TrackerDefinition;
using Sern.ServiceImplementation.TrackerDefinition.Data;

namespace Sern.ServiceImplementation
{
    public abstract class AbstractHostBase : IDisposable
    {
        private DateTime _instantiatedTime = DateTime.UtcNow;
        private ServiceHost hostListener;        
        protected string HostName { get; private set; }

        public AbstractHostBase(string hostName)
        {
            HostName = hostName;
        }

        public void Initialize()
        {
            StartAndRegisterHostListener();
        }

        //protected Guid HostId
        //{
        //    get { return _hostId; }
        //}

        protected abstract ClientType HostType { get; }

        protected string relativeUri
        {
            get
            {
                var trackerHostBindingScheme = ComponentLocator.Unity.Resolve<IBindingFactory>()[HostType]();
                Uri relativeUri;
                var baseUri = GetHostBaseAndRelativeUri(trackerHostBindingScheme, out relativeUri);
                return relativeUri.OriginalString;
            }
            
        }

        protected  string baseUri
        {
            get
            {
                var trackerHostBindingScheme = ComponentLocator.Unity.Resolve<IBindingFactory>()[HostType]();
                Uri relativeUri;
                var baseUri = GetHostBaseAndRelativeUri(trackerHostBindingScheme, out relativeUri);
                return baseUri.AbsoluteUri;
            }
        }

        protected  string AbsoluteUri
        {
            get
            {
                var trackerHostBindingScheme = ComponentLocator.Unity.Resolve<IBindingFactory>()[HostType]();
                Uri relativeUri;
                var baseUri = GetHostBaseAndRelativeUri(trackerHostBindingScheme, out relativeUri);
                var absolutUri = new Uri(baseUri, relativeUri).AbsoluteUri;
                return absolutUri;
            }
        }



        protected virtual void StartAndRegisterHostListener()
        {
            var listener = ComponentLocator.Unity.Resolve<IListenerFactory>().Create(new Uri(baseUri), new Uri(relativeUri, UriKind.Relative), ClientType.TrackerHost, this);
            listener.Open();
        }

        private Uri GetHostBaseAndRelativeUri(BindingScheme bindingScheme,
                                                     out Uri relativeUri)
        {
            var baseUriBuilder = new UriBuilder();
            baseUriBuilder.Host = HostName;
            baseUriBuilder.Scheme = bindingScheme.Scheme;
            baseUriBuilder.Port = bindingScheme.Port ?? -1;            
            relativeUri = new Uri(HostType.ToString(), UriKind.Relative);
            return baseUriBuilder.Uri;
        }

        public virtual void Dispose()
        {            
            hostListener.Close();
            DisposeMembers();
        }

        protected virtual void DisposeMembers()
        {
            var clientInfoRepository = ComponentLocator.Unity.Resolve<IRepository<Client>>();

            var trackerHostBindingScheme = ComponentLocator.Unity.Resolve<IBindingFactory>()[HostType]();

         
            
            var hostMemberIds = (from _ in clientInfoRepository.Records
                                 where _.ClientHostUri == AbsoluteUri
                                 select _.Id).ToArray();           
        }

        protected abstract void DisposeMember(Guid id);
    }
}
